package edu.utexas.esel.jgraphpad.archpadplugin;

import java.awt.Component;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.jgraph.JGraphEditor;
import com.jgraph.JGraphpad;
import com.jgraph.editor.JGraphEditorAction;
import com.jgraph.editor.JGraphEditorTool;
import com.jgraph.editor.JGraphEditorAction.Bundle;
import com.jgraph.editor.factory.JGraphEditorToolbox;
import com.jgraph.editor.factory.JGraphEditorComboBox.BorderComboFactoryMethod;
import com.jgraph.editor.factory.JGraphEditorComboBox.DashPatternComboFactoryMethod;
import com.jgraph.editor.factory.JGraphEditorComboBox.LineDecorationComboFactoryMethod;
import com.jgraph.editor.factory.JGraphEditorComboBox.LineWidthComboFactoryMethod;
import com.jgraph.pad.action.JGraphpadCellAction;
import com.jgraph.pad.action.JGraphpadFormatAction;
import com.jgraph.pad.factory.JGraphpadPane;
import com.jgraph.pad.factory.JGraphpadComboBox.ColorComboFactoryMethod;
import com.jgraph.pad.factory.JGraphpadComboBox.VertexShapeComboFactoryMethod;

/**
 * This class is a manager for that assures that only tools ans actions
 * relevant to ArchPad models are enabled if the currently focused graph
 * represents such a model.
 *
 * @author svetoslavganov@mail.utexas.edu
 *
 */
public class ToolsAndActionsManager {

	private static Set<String> sIrrelevantTools = new HashSet<String>();
	static {
		sIrrelevantTools.add(JGraphpad.NAME_VERTEXTOOL);
		sIrrelevantTools.add(JGraphpad.NAME_ROUNDEDTOOL);
		sIrrelevantTools.add(JGraphpad.NAME_CIRCLETOOL);
		sIrrelevantTools.add(JGraphpad.NAME_DIAMONDTOOL);
		sIrrelevantTools.add(JGraphpad.NAME_TRIANGLETOOL);
		sIrrelevantTools.add(JGraphpad.NAME_CYLINDERTOOL);
		sIrrelevantTools.add(JGraphpad.NAME_IMAGETOOL);
		sIrrelevantTools.add(JGraphpad.NAME_HEAVYTOOL);
		sIrrelevantTools.add(JGraphpad.NAME_EDGETOOL);
		sIrrelevantTools.add(JGraphpad.NAME_ORTHOGONALEDGETOOL);
		sIrrelevantTools.add(BorderComboFactoryMethod.NAME);
		sIrrelevantTools.add(DashPatternComboFactoryMethod.NAME);
		sIrrelevantTools.add(LineDecorationComboFactoryMethod.NAME);
		sIrrelevantTools.add(LineWidthComboFactoryMethod.NAME);
		sIrrelevantTools.add(ColorComboFactoryMethod.NAME);
		sIrrelevantTools.add(VertexShapeComboFactoryMethod.NAME);
	}

	private static Set<String> sIrrelevantActions = new HashSet<String>();
	static {
		sIrrelevantActions.add(JGraphpadCellAction.NAME_TOFRONT);
		sIrrelevantActions.add(JGraphpadCellAction.NAME_TOBACK);
		sIrrelevantActions.add(JGraphpadCellAction.NAME_GROUP);
		sIrrelevantActions.add(JGraphpadCellAction.NAME_UNGROUP);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_FONT);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_FONTPLAIN);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_FONTBOLD);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_FONTITALIC);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_FONTUNDERLINE);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_SWITCHALIGNTOP);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_SWITCHALIGNLEFT);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_SWITCHALIGNCENTER);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_SWITCHALIGNRIGHT);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_SWITCHALIGNBOTTOM);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_SWITCHSHAPECIRCLE);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_SWITCHSHAPECYLINDER);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_SWITCHSHAPEDIAMOND);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_SWITCHSHAPERECTANGLE);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_SWITCHSHAPEROUNDED);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_SWITCHSHAPETRIANGLE);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_CELLIMAGE);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_CELLIMAGEURL);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_TOGGLESTRETCHCELLIMAGE);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_CLEARCELLIMAGE);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_CELLBORDERCOLOR);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_CELLBORDERWIDTH);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_CELLINSET);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_CLEARCELLBORDER);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_SWITCHALIGNTOP);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_SWITCHLABELBOTTOM);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_SWITCHLABELCENTER);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_SWITCHALIGNLEFT);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_SWITCHLABELMIDDLE);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_SWITCHLABELRIGHT);
		sIrrelevantActions.add(JGraphpadFormatAction.NAME_SWITCHLABELTOP);
	}
	
	private JGraphEditor mEditor;

	private JGraphEditorToolbox mToolbox;

	public ToolsAndActionsManager(JGraphEditor editor) {
        mEditor = editor;
	}

	/**
	 * Updates the state of the application tools, combos and actions to disable
	 * irrelevant ones if the currently focused graph is an ArchPad model. It
	 * also changes the current tool if it is no longer applciable in the 
	 * current context.
	 *
	 * Note: Since the irrelevant tools and actions are hard coded in this
	 *       class it is possible other plugins to add tools and actions
	 *       irrelevant to ArchPad models. However, most of the hard coded
	 *       values represent facilities introduced by the base application.
	 * 
	 */
	public void update() {
		boolean enabled = !Utils.isCurrentArchPadDiagram();
		setIrrelevantToArchPadActionsState(enabled);
		setIrrelevantToArchPadToolsState(enabled);
		setIrrelevantToArchPadCombosState(enabled);
		setSelectToolActiveIfSelectedToolNotApplicable();
	}

	/**
	 * Sets the state of actions irrelevant to ArchPad.
	 *
	 * @param enabled The state.
	 */
	@SuppressWarnings("unchecked")
	// JGraphpad uses raw types
	private void setIrrelevantToArchPadActionsState(boolean enabled) {
		List<Bundle> bundles = mEditor.getKit().getBundles();
		for (Bundle bundle : bundles) {
			for (JGraphEditorAction action : bundle.getActions()) {
				String name = action.getName();
				if (sIrrelevantActions.contains(name)) {
					action.setEnabled(enabled);	
				}
			}
		}
	}

	/**
	 * Sets the state of tools irrelevant to ArchPad.
	 *
	 * @param enabled The state.
	 */
	@SuppressWarnings("unchecked")
	// JGraphpad uses raw types
	private void setIrrelevantToArchPadToolsState(boolean enabled) {
		Set<Map.Entry<String, ?>> set = mEditor.getKit().getTools().entrySet();
		for (Map.Entry<String, ?> entry : set) {
			String name = entry.getKey();
			if (sIrrelevantTools.contains(name)) {
				JGraphEditorTool tool = (JGraphEditorTool) entry.getValue();
				tool.setEnabled(enabled);
			}
		}
	}

	/**
	 * Sets the state of combos irrelevant to ArchPad.
	 *
	 * @param enabled The state.
	 */
	private void setIrrelevantToArchPadCombosState(boolean enabled) {
		for (Component component : getToolbox().getComponents()) {
	        if (sIrrelevantTools.contains(component.getName())) {
				component.setEnabled(enabled);
			}
		}
	}

	/**
	 * Sets the selected tool a the selectTool if the former is not applicable
	 * in the current context.
	 */
	private void setSelectToolActiveIfSelectedToolNotApplicable() {	
		JGraphEditorTool selectedTool = mToolbox.getSelectionTool();
		if (!selectedTool.isEnabled()) {
			String key = JGraphpad.NAME_SELECTTOOL;
			JGraphEditorTool selectTool = mEditor.getKit().getTool(key);
			getToolbox().setSelectionTool(selectTool);
		}
	}

	/**
	 * Return the toolbox of the application.
	 *
	 * @return The toolbox.
	 */
	private JGraphEditorToolbox getToolbox() {
		if (mToolbox == null) {
		    String key = JGraphpadPane.FactoryMethod.NODENAME_TOOLBOX;
            mToolbox = (JGraphEditorToolbox) mEditor.getSettings()
                .getObject(key);
		}
		return mToolbox;
	}
}
